#include "stdafx.h"
#include "HookProc.h"
#ifdef _MANAGED
#pragma managed(push, off)
#endif

// required for hooks
HHOOK hhook;

// to send messaged back
HWND hWndHost = NULL;

// So we don't search when we're in the host
BOOL isHost = FALSE;

BOOL bTopLevel = FALSE;


HookWindow hwDragonBar	= { NULL, NULL} ;
HookWindow hwDNS		= { NULL, NULL} ;


BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved )
{
	
	switch(ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		{

			TCHAR str[1024];
			GetModuleFileName(0 , str, 1024);      

			if( wcsstr(str , L"QuickSwitch.exe") || wcsstr(str , L"TestShutdown.exe") ) 
			{
				isHost = TRUE;
				dbg(L"IsHost",isHost);
			}

			if( isHost || wcsstr(str , L"natspeak.exe"))
			{

				HANDLE hMapFile = CreateFileMapping(
					INVALID_HANDLE_VALUE,    // use paging file
					NULL,                    // default security 
					PAGE_READWRITE,          // read/write access
					0,                       // max. object size 
					BUF_SIZE,                // buffer size  
					szMapFileName);                 // name of mapping object

				if (hMapFile == NULL || hMapFile == INVALID_HANDLE_VALUE) 
				{ 
					dbg(L"Could not create file mapping object (%d).\n", GetLastError());
					return FALSE;
				}

				 LPTSTR pBuf = (LPTSTR) MapViewOfFile(hMapFile,   // handle to mapping object
					FILE_MAP_ALL_ACCESS, // read/write permission
					0,                   
					0,                   
					BUF_SIZE);    

				hhook = *(HHOOK *)pBuf;

				pBuf++;
				hWndHost = *(HWND *)pBuf;
				dbg(L"Host Window = %x",hWndHost);

				return TRUE;
			}
			return FALSE;
		}
	case DLL_PROCESS_DETACH:
		{
			if (hwDNS.targetWindow != NULL)
			{
				SetWindowLongPtr(hwDNS.targetWindow , GWLP_WNDPROC,(LONG)(LONG_PTR) hwDNS.origWndProc);
				hwDNS.targetWindow = NULL;
				hwDNS.origWndProc = NULL;
			}

			if (hwDragonBar.targetWindow != NULL)
			{
				SetWindowLongPtr(hwDragonBar.targetWindow , GWLP_WNDPROC,(LONG)(LONG_PTR) hwDragonBar.origWndProc);
				hwDragonBar.targetWindow = NULL;
				hwDragonBar.origWndProc = NULL;
			}

		}
		return TRUE;
	}
	return TRUE;
}


#ifdef _MANAGED
#pragma managed(pop)
#endif


LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) 
{   
	if (nCode < 0 || isHost)
	{
		return CallNextHookEx(hhook, nCode, wParam, lParam); 
	}

	if((!hwDNS.targetWindow  || !hwDragonBar.targetWindow) && HCBT_CREATEWND == nCode)
	{
		bTopLevel = TRUE;
		EnumWindows( EnumProc, 0);         
	}

	return CallNextHookEx(hhook, nCode, wParam, lParam); 
} 

BOOL CALLBACK EnumProc( HWND hwnd, LPARAM lParam)
{
#pragma warning( push )
#pragma warning( disable : 4244 )

	if (hwDNS.targetWindow != NULL && hwDragonBar.targetWindow !=NULL ) return TRUE;
	DWORD dwId = 0;
	GetWindowThreadProcessId(hwnd , &dwId);           
	if(dwId  == GetCurrentProcessId())
	{
		TCHAR className[1024];
		GetClassName(hwnd,className,1024);
		WNDPROC wproc = NULL;

		if (!_wcsicmp(className,L"#32770"))
		{
			TCHAR windowText[1024];
			GetWindowText(hwnd,windowText,1024);
			if (!_wcsicmp(windowText,L"DragonBar"))
			{
				dbg(L"Loader::EnumProc Found DragonBar =%P",hwnd);
				wproc = (WNDPROC)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_WNDPROC);
				if (wproc != WndProc)
				{
					dbg(L"Setting wndProc",L"");
					hwDragonBar.origWndProc =  wproc;
					hwDragonBar.targetWindow = hwnd;
					if (!SetWindowLongPtr(hwnd,GWLP_WNDPROC,(LONG_PTR)WndProc))
					{
						dbg(L"Loader::EnumProc failed to set=%d",GetLastError());
					}
				}
			}
			if (!_wcsicmp(windowText,L"Dragon NaturallySpeaking"))
			{
				dbg(L"Loader::EnumProc Found DNS =%P",hwnd);
				wproc = (WNDPROC)(LONG_PTR)GetWindowLongPtr(hwnd, GWLP_WNDPROC);
				if (wproc != WndProc)
				{
					dbg(L"Setting wndProc",L"");
					hwDNS.origWndProc = wproc;
					hwDNS.targetWindow = hwnd;
					if (!SetWindowLongPtr(hwnd , GWLP_WNDPROC , (LONG_PTR)WndProc))
					{
						dbg(L"Loader::EnumProc failed to set=%d",GetLastError());
					}
				}
			}
		}

		if(bTopLevel)
		{
			bTopLevel = FALSE;
			EnumChildWindows(hwnd, EnumProc, 0 );
		}
	}
	return TRUE;
	#pragma warning( pop )
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT i , WPARAM w, LPARAM l)
{
	if ( hwnd ==  hwDNS.targetWindow && i == WM_QUERYENDSESSION)
	{
		dbg(L"Got WM_QUERYENDSESSION %P",hwnd);
		SendMessage(hWndHost, i ,w , l);
	}

	if (hwnd == hwDragonBar.targetWindow && i == WM_DESTROY)
	{
		dbg(L"Got WM_DESTROY %P",hwnd);
		SendMessage(hWndHost, WM_CLOSE  ,w , l);
	}
	WNDPROC lpPrevWndFunc =  (hwnd == hwDNS.targetWindow) ? hwDNS.origWndProc :  hwDragonBar.origWndProc;
	if (lpPrevWndFunc != NULL)
	{
		LRESULT lr = CallWindowProc( lpPrevWndFunc  , hwnd , i , w , l);
		return lr;
	}
	dbg(L"Got nothing, big trouble",hwnd);
	//ASSERT(0);
	return 0;
}
